package repository

import (
	"errors"
	"fmt"
	"invitation/internal/http/utils"
	"invitation/internal/model"
	"invitation/internal/repository/cache"

	"github.com/rs/zerolog/log"
	"gorm.io/gorm"
)

type FirstTimeTeacherInfoRepository interface {
	Create(info *model.FirstTimeTeacherInfo) (uint, error)
	Update(info *model.FirstTimeTeacherInfo) error
	Delete(id uint) error

	FindListAll() ([]model.FirstTimeTeacherInfo, error)
	FindOneByTeacherInfoID(id uint) (*model.FirstTimeTeacherInfo, error)
	FindOneByTeacherID(teacherID string) (*model.FirstTimeTeacherInfo, error)
	FindListByTeacherName(name string) ([]model.FirstTimeTeacherInfo, error)
}

type firstTimeTeacherInfoRepository struct {
	*BaseRepository
}

func newFirstTimeTeacherInfoRepository(db *gorm.DB) *firstTimeTeacherInfoRepository {
	return &firstTimeTeacherInfoRepository{
		BaseRepository: newBaseRepository(db),
	}
}

func (ftir *firstTimeTeacherInfoRepository) Create(info *model.FirstTimeTeacherInfo) (uint, error) {

	// 使用事务确保数据一致性
	err := ftir.GetDB().Transaction(func(tx *gorm.DB) error {
		// 先创建记录
		if err := tx.Create(info).Error; err != nil {
			return err
		}

		// 生成TeacherID并更新
		info.TeacherID = utils.GenerateTeacherID(info.ID)
		return tx.Model(info).Update("teacher_id", info.TeacherID).Error
	})

	if err != nil {
		return 0, err
	}

	return info.ID, nil
}
func (ftir *firstTimeTeacherInfoRepository) Update(info *model.FirstTimeTeacherInfo) error {
	// 1. 获取旧数据，用于零值比较
	var oldInfo model.FirstTimeTeacherInfo
	if err := ftir.GetDB().Where("teacher_id = ?", info.TeacherID).First(&oldInfo).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return fmt.Errorf("teacher with ID %d not found, cannot update", info.ID)
		}
		return err
	}
	updateData := make(map[string]interface{})

	// 检查 Name
	if info.Name != "" {
		updateData["name"] = info.Name
	}

	// 检查 Desc
	if info.Desc != "" {
		updateData["desc"] = info.Desc
	}

	// ID, CreatedAt, DeletedAt 不应在此处手动更新
	// UpdatedAt 会被 GORM 自动处理

	// 3. 执行更新
	// 如果 updateData 为空，则无需执行数据库操作
	if len(updateData) == 0 {
		return nil // 或者返回一个错误，表示没有提供任何有效更新字段
	}
	info.ID = oldInfo.ID
	log.Debug().Msgf("id: %d, name: %s, desc: %s", info.ID, info.Name, info.Desc)
	// 使用 Updates 方法，它会自动处理 UpdatedAt
	return ftir.GetDB().Model(&oldInfo).Updates(updateData).Error
}
func (ftir *firstTimeTeacherInfoRepository) Delete(id uint) error {
	return ftir.GetDB().Delete(&model.FirstTimeTeacherInfo{}, id).Error
}

func (ftir *firstTimeTeacherInfoRepository) FindListAll() ([]model.FirstTimeTeacherInfo, error) {
	var infoList []model.FirstTimeTeacherInfo
	err := ftir.GetDB().Find(&infoList).Error
	if err != nil {
		return nil, err
	}
	return infoList, nil
}

func (ftir *firstTimeTeacherInfoRepository) FindOneByTeacherInfoID(id uint) (*model.FirstTimeTeacherInfo, error) {
	var info model.FirstTimeTeacherInfo
	err := ftir.GetDB().First(&info, id).Error
	if err != nil {
		return nil, err
	}
	return &info, nil
}

func (ftir *firstTimeTeacherInfoRepository) FindOneByTeacherID(teacherID string) (*model.FirstTimeTeacherInfo, error) {
	var info model.FirstTimeTeacherInfo
	err := ftir.GetDB().Where("teacher_id = ?", teacherID).First(&info).Error
	if err != nil {
		return nil, err
	}
	return &info, nil
}

func (ftir *firstTimeTeacherInfoRepository) FindListByTeacherName(name string) ([]model.FirstTimeTeacherInfo, error) {
	var infoList []model.FirstTimeTeacherInfo
	err := ftir.GetDB().Where("name LIKE ?", "%"+name+"%").Find(&infoList).Error
	if err != nil {
		return nil, err
	}
	return infoList, nil
}

// 缓存版本
type cachedFirstTimeTeacherInfoRepository struct {
	*BaseCachedRepository
}

func newCachedFirstTimeTeacherInfoRepository(db *gorm.DB, cache *cache.LRU, repoName string) *cachedFirstTimeTeacherInfoRepository {
	repo := newFirstTimeTeacherInfoRepository(db)
	return &cachedFirstTimeTeacherInfoRepository{
		BaseCachedRepository: newBaseCachedRepository(repo, cache, repoName),
	}
}

func (cftir *cachedFirstTimeTeacherInfoRepository) BaseRepo() *firstTimeTeacherInfoRepository {
	return cftir.GetBaseRepo().(*firstTimeTeacherInfoRepository)
}

var (
	teacherListAllKey = "teacher_list_all"
	teacherIDKey      = "teacher_id"
	teacherNameKey    = "teacher_name"
)

func (cftir *cachedFirstTimeTeacherInfoRepository) Create(info *model.FirstTimeTeacherInfo) (uint, error) {
	cftir.mutex.Lock()
	defer cftir.mutex.Unlock()

	id, err := cftir.BaseRepo().Create(info)
	if err != nil {
		return 0, err
	}

	if cftir.GetCache() == nil {
		return id, err
	}

	// 清理列表缓存
	cacheKey := cftir.GenerateCacheKey(teacherListAllKey)
	cftir.GetCache().Remove(cacheKey)

	return id, err
}

func (cftir *cachedFirstTimeTeacherInfoRepository) Update(info *model.FirstTimeTeacherInfo) error {
	cftir.mutex.Lock()
	defer cftir.mutex.Unlock()

	// 2. 获取旧数据，用于零值比较和缓存清理
	var oldInfo model.FirstTimeTeacherInfo
	if err := cftir.BaseRepo().GetDB().Where("teacher_id = ?", info.TeacherID).First(&oldInfo).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return fmt.Errorf("teacher with ID %d not found, cannot update", info.ID)
		}
		return err
	}

	// 3. 执行更新
	err := cftir.BaseRepo().Update(info)
	if err != nil {
		return err
	}

	// 4. 清理缓存
	if cftir.GetCache() == nil {
		return nil
	}

	// 清理列表缓存
	listCacheKey := cftir.GenerateCacheKey(teacherListAllKey)
	cftir.GetCache().Remove(listCacheKey)

	// 清理旧 TeacherID 缓存
	oldTeacherIDKey := cftir.GenerateCacheKey(teacherIDKey, oldInfo.TeacherID)
	cftir.GetCache().Remove(oldTeacherIDKey)

	// 清理旧 Name 缓存
	oldNameKey := cftir.GenerateCacheKey(teacherNameKey, oldInfo.Name)
	cftir.GetCache().Remove(oldNameKey)

	// 更新新 TeacherID 缓存
	newTeacherIDKey := cftir.GenerateCacheKey(teacherIDKey, info.TeacherID)
	cftir.GetCache().Add(newTeacherIDKey, info)

	// 更新新 Name 缓存
	newNameKey := cftir.GenerateCacheKey(teacherNameKey, info.Name)
	cftir.GetCache().Add(newNameKey, info)

	return nil
}

func (cftir *cachedFirstTimeTeacherInfoRepository) Delete(id uint) error {
	cftir.mutex.Lock()
	defer cftir.mutex.Unlock()

	// 先获取要删除的记录，以便清理缓存
	var info model.FirstTimeTeacherInfo
	if err := cftir.BaseRepo().GetDB().First(&info, id).Error; err != nil {
		return err
	}

	err := cftir.BaseRepo().Delete(id)
	if err != nil {
		return err
	}

	if cftir.GetCache() == nil {
		return err
	}

	// 清理相关缓存
	listCacheKey := cftir.GenerateCacheKey(teacherListAllKey)
	cftir.GetCache().Remove(listCacheKey)

	teacherIDCacheKey := cftir.GenerateCacheKey(teacherIDKey, info.TeacherID)
	cftir.GetCache().Remove(teacherIDCacheKey)

	nameCacheKey := cftir.GenerateCacheKey(teacherNameKey, info.Name)
	cftir.GetCache().Remove(nameCacheKey)

	return nil
}

func (cftir *cachedFirstTimeTeacherInfoRepository) FindListAll() ([]model.FirstTimeTeacherInfo, error) {
	if cftir.GetCache() == nil {
		return cftir.BaseRepo().FindListAll()
	}

	cacheKey := cftir.GenerateCacheKey(teacherListAllKey)
	if cache, ok := cftir.GetCache().Get(cacheKey); ok {
		if infoList, ok := cache.([]model.FirstTimeTeacherInfo); ok {
			return infoList, nil
		}
	}

	infoList, err := cftir.BaseRepo().FindListAll()
	if err == nil {
		cftir.GetCache().Add(cacheKey, infoList)
	}

	return infoList, err
}

func (cftir *cachedFirstTimeTeacherInfoRepository) FindOneByTeacherInfoID(id uint) (*model.FirstTimeTeacherInfo, error) {
	if cftir.GetCache() == nil {
		return cftir.BaseRepo().FindOneByTeacherInfoID(id)
	}
	cacheKey := cftir.GenerateCacheKey(teacherIDKey, id)
	if cache, ok := cftir.GetCache().Get(cacheKey); ok {
		if info, ok := cache.(*model.FirstTimeTeacherInfo); ok {
			return info, nil
		}
	}
	info, err := cftir.BaseRepo().FindOneByTeacherInfoID(id)
	if err == nil {
		cftir.GetCache().Add(cacheKey, info)
	}
	return info, err
}
func (cftir *cachedFirstTimeTeacherInfoRepository) FindOneByTeacherID(teacherID string) (*model.FirstTimeTeacherInfo, error) {
	if cftir.GetCache() == nil {
		return cftir.BaseRepo().FindOneByTeacherID(teacherID)
	}

	cacheKey := cftir.GenerateCacheKey(teacherIDKey, teacherID)
	if cache, ok := cftir.GetCache().Get(cacheKey); ok {
		if info, ok := cache.(*model.FirstTimeTeacherInfo); ok {
			return info, nil
		}
	}

	info, err := cftir.BaseRepo().FindOneByTeacherID(teacherID)
	if err == nil {
		cftir.GetCache().Add(cacheKey, info)
	}

	return info, err
}

func (cftir *cachedFirstTimeTeacherInfoRepository) FindListByTeacherName(name string) ([]model.FirstTimeTeacherInfo, error) {
	if cftir.GetCache() == nil {
		return cftir.BaseRepo().FindListByTeacherName(name)
	}

	cacheKey := cftir.GenerateCacheKey(teacherNameKey, name)
	if cache, ok := cftir.GetCache().Get(cacheKey); ok {
		if infoList, ok := cache.([]model.FirstTimeTeacherInfo); ok {
			return infoList, nil
		}
	}

	infoList, err := cftir.BaseRepo().FindListByTeacherName(name)
	if err == nil {
		cftir.GetCache().Add(cacheKey, infoList)
	}

	return infoList, err
}

func NewFirstTimeTeacherInfoRepositoryWithCache(db *gorm.DB, cache *cache.LRU, repoName string) Repository {
	return newCachedFirstTimeTeacherInfoRepository(db, cache, repoName)
}
